package com.example.demo.study;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

public class LockSynch {
    private static final ReentrantLock lock = new ReentrantLock();

    // ReentrantLock.tryLock()方法获取到锁的线程不会阻塞
    public void method1(String name) {
        if (lock.tryLock()) {
            try {
                System.out.println(name + "获取到锁");
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                lock.unlock();
                System.out.println(name + "成功释放锁");
            }
        } else {
            System.out.println(name + "未获取到锁");
        }
    }

    public void method2(String name) {
        boolean tryLock = lock.tryLock();
        try {
            if (tryLock) {
                System.out.println(name + "获取到锁");
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println(name + "未获取到锁"); // 此时没拿到锁也会调用finally
            }
        } finally {
            // 错误的 调用lock.unlock必须拿到锁 java.lang.IllegalMonitorStateException
            lock.unlock();
        }
    }

    // ReentrantLock.lock()方法获取到锁的线程会阻塞，进入等待状态，和synchronized一样
    public void method3(String name) {
        lock.lock();
        System.out.println(name + "获取到锁");
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.unlock();
        System.out.println(name + "成功释放锁");
    }

    public void method4(String name) {
        synchronized (LockSynch.class) { // synchronized会阻塞线程，进入等待状态
            System.out.println(name + "获取到锁");
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + "成功释放锁");
        }
    }

    ExecutorService executor = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        LockSynch lockSynch = new LockSynch();
//        lockSynch.test1();
//        lockSynch.test2();
//        lockSynch.test3();
//        lockSynch.test4();
        lockSynch.intercept();

    }

    public void intercept() {
        Thread thread = new Thread(() -> {
            try {
                lock.lockInterruptibly(); // 如果可以获取锁则获取锁并返回，如果获取不到则阻塞等待，可以响应其他线程的中断
                System.out.println("获取到锁"); // 上面一行代码抛出InterruptedException
                Thread.sleep(5000); // 模拟工作
            } catch (InterruptedException e) {
                System.out.println("线程在等待锁定时被中断");
            } finally {
                if (lock.isHeldByCurrentThread()) lock.unlock();
            }
        });
        lock.lock();
        thread.start(); // 先让主线程获取锁
        // 暂停主线程，留一定时间给子线程获取锁
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断子线程的等待，让他响应中断并退出等待状态
        thread.interrupt();
        // 主线程继续执行
        System.out.println("主线程结束");
    }

    public void test4() {
        executor.execute(() -> {
            new LockSynch().method4("线程1");
        });
        executor.execute(() -> {
            new LockSynch().method4("线程2");
        });
        executor.shutdown();
    }

    public void test3() {
        executor.execute(() -> {
            new LockSynch().method3("线程1");
        });
        executor.execute(() -> {
            new LockSynch().method3("线程2");
        });
        executor.shutdown();
    }

    public void test2() {
        executor.execute(() -> {
            new LockSynch().method2("线程1");
        });
        executor.execute(() -> {
            new LockSynch().method2("线程2");
        });
        executor.shutdown();
    }

    public void test1() {
        executor.execute(() -> {
            new LockSynch().method1("线程1");
        });
        executor.execute(() -> {
            new LockSynch().method1("线程2");
        });
        executor.shutdown();
    }


}
